#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include "proto.h"
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#define NAMESIZE 1024


#define MSG_EXCEPT 020000
enum{
	STATE_SND=1,
	STATE_RCV,
	STATE_EX,
	STATE_T,
};

struct ftp_s_st{
	int state;
	int id;
	union msg_un msg;	
	char fname[NAMESIZE];
	char errsoure[NAMESIZE];
	int flag;
	int fd;
};


static void drive(struct ftp_s_st* me){
	int ret,len;
	switch(me->state){
		case STATE_RCV:
			{
				msg_path_t msg_path;
				ret=msgrcv(me->id,&msg_path,sizeof(msg_path_t)-sizeof(long),PATH,0);
				if(ret<0){
					me->state=STATE_EX;
					strncpy(me->errsoure,"msgrcv()",NAMESIZE);
					return ;
				}
				strncpy(me->fname,msg_path.path,NAMESIZE);
				me->state=STATE_SND;
				me->fd=open(me->fname,O_RDONLY);
				if(me->fd<0){
					strncpy(me->errsoure,"open111",NAMESIZE);
					me->state=STATE_EX;
				}
			}
			
			break;
		case STATE_SND:
			{
				msg_data_t msgdata;
				msgdata.mtype=DATA;
				ret=read(me->fd,msgdata.data,DATASIZE);
				if(ret<0){
					if(errno==EINTR||errno==EAGAIN){
						me->state=STATE_SND;
					}
					else{
					strncpy(me->errsoure,"read",NAMESIZE);
						
						me->state=STATE_EX;
					}
				}
				else if(ret==0){
					msg_eot_t msgeot;
					msgeot.mtype=EOT;
					len=msgsnd(me->id,&msgeot,sizeof(msg_eot_t)-sizeof(long),0);
					if(len<0){
						strncpy(me->errsoure,"eot msgsnd",NAMESIZE);
						me->state=STATE_EX;
					}
					me->state=STATE_T;
				}
				else {
					len=msgsnd(me->id,&msgdata,sizeof(msg_data_t)-sizeof(long),0);
					if(len<0){
						strncpy(me->errsoure,"eot msgsnd",NAMESIZE);
						me->state=STATE_EX;
					}
					me->state=STATE_SND;
				}
			}
			break;
		case STATE_EX:
			{
				int fd;
				fd=open("/tmp/out",O_CREAT|O_TRUNC|O_RDWR,0660);
				write(fd,me->errsoure,NAMESIZE);
				close(fd);
				me->state=STATE_T;
			}
			break;
		case STATE_T:
			{
				close(me->fd);
				me->state=STATE_RCV;
			}
			break;
		default:abort();
			break;
	}


}

static void mydaemon(int msgid){
	pid_t pid;
	pid=fork();

	if(pid<0){
		perror("fork()");
		exit(1);
	}
	else if(pid==0){
		FILE* fp;
	key_t key;
		key=ftok(KEYPATH,KEYPROJ);
		if(key<0){
			perror("ftok()");
			exit(1);
		}
		msgid=msgget(key,0660|IPC_CREAT);
		if(msgid<0){
			perror("msgget()");
			exit(1);
		}
		fp=tmpfile();
		int fd;
		fd=fileno(fp);
		dup2(fd,0);
		dup2(fd,1);
		dup2(fd,3);
		close(fd);
		setsid();
		chdir("/");
		umask(0);
		struct ftp_s_st ftps;
		ftps.state=STATE_RCV;
		ftps.id=msgid;
		ftps.flag=1;
		while(1){
			drive(&ftps);
		}
		msgctl(ftps.id,IPC_RMID,NULL);
		exit(0);

	}
	else{
		return ;
	}
}


int main(){
	int msgid;
	mydaemon(msgid);
	exit(0);

}

